package cr.ac.una.escinf.ia.classes;

import cr.ac.una.escinf.ia.classes.Card.Rank;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;

/**
 *
 * @author Grupo de IA - 2011
 */
public class Hand {

    private int pos;
    private Card[] cards;

    public Hand(Card c1, Card c2) {
        cards = new Card[2];
        pos = 0;
        add(c1);
        add(c2);
    }
    
    public int[] getValue(Card[] input){
        ArrayList<Card> lista = new ArrayList<Card>();
        if (input != null) {// I need check the value , while i have 2 cards
            lista.addAll(Arrays.asList(input));
        }
        lista.add(cards[0]);
        lista.add(cards[1]);

        Collections.sort(lista);
        input = new Card[lista.size()];
        for (int i = 0; i < lista.size(); i++) {
            input[i] = lista.get(i);
        }
        //
        //      
        if (isRoyalFlush(input)) //Steven 9//  hay que revisar jaja
        {
            return royalFlush(input);
        }
        if (isStraightFlush(input)) //Listo
        {
            return straightFlush(input);
        }
        if (isPoker(input)) //Eddy (Listo) 7
        {
            return poker(input);
        }
        if (isFull(lista)) // Listo
        {

            return full(lista);
        }

        if (isFlush(input)) //listo 5
        {
            return flush(input);
        }
         if (isStraight(lista)) //listo 4
        {
           
        return straight(lista);
        }
        if (threeOfAKind(lista)) //listo 3
        {
            return threeofK(lista);
            //return null;
        }
         if (isTwoPairs(input)) //Christopher 2
         {
        return twoPairs(input);
        }
        if (isPair(input)) //Steven 1 (Listo)
        {
            return pair(input);
        }
        return highCard(lista); //listo

    }

    public final void add(Card card) {
        cards[pos++ % cards.length] = card; // Cola circular 
    }

    public void replace(Card i, Card o) {
        if (cards[0] == i) {
            cards[0] = o;
        }
        if (cards[1] == i) {
            cards[1] = o;
        }
    }

    public Hand copy() {
        Hand newHand = new Hand(cards[0], cards[1]);
        // crea una mano con las mismas cartas que la original
        return newHand;
    }

    private boolean isPoker(Card[] input) {
        
        if (input.length < 4) {
            return false;
        }
        Rank val = input[0].getValue();
        int cont = 0;
        for (Card piv : input) {
            if (piv.getValue() == val) {
                cont++;
            }
        }
        if (cont == 4) {
            return true;
        }
        val = input[1].getValue();
        cont = 0;
        for (Card piv : input) {
            if (piv.getValue() == val) {
                cont++;
            }
        }
        Card temp = input[0];
        input[0] = input[1];
        input[1] = temp;
        return cont == 4;
    }

    private int[] poker(Card[] input) {
        int[] resp = new int[3];
        resp[0] = 7;
        resp[1] = input[0].getValue().ordinal();
        for (Card piv : input) {
            if (piv.getValue().ordinal() != resp[1]) {
                resp[2] = piv.getValue().ordinal();
                break;
            }
        }
        return resp;
    }

    private boolean isStraightFlush(Card[] input) { // le cambie el nombre 
        if (input.length < 4) {                   // fue hecho por steven
            return false;                         // Att Sneasell21
        }
        //        
        int encontrados = 0;
        Rank valor;
        for (int i = 0; i < 3; i++) {
            Card actual = input[i];
            valor = input[i].getValue();
            encontrados = 1;
            for (int j = i + 1; j < input.length; j++) {
                Card tmp = input[j];
                if (actual.getSult().equals(tmp.getSult()) && valor.ordinal() + encontrados == tmp.getValue().ordinal()) {
                    encontrados++;
                }
            }
            if (encontrados == 5) { // el 5to elemento es la carta inicial, asi suman
                // las 5 cartas en escalera del mismo color.
                return true;
            }
        }
        return false;
    }

    private int[] royalFlush(Card[] input) {
        int[] resp = new int[2];
        resp[0] = 9;
        //
        int encontrados = 0;
        Rank valor;
        for (int i = 0; i < 3; i++) {
            Card actual = input[i];
            valor = input[i].getValue();
            encontrados = 1;
            for (int j = i + 1; j < input.length; j++) {
                Card tmp = input[j];
                if (actual.getSult().equals(tmp.getSult()) && valor.ordinal() + encontrados == tmp.getValue().ordinal()) {
                    encontrados++;
                }
            }
            if (encontrados == 5) {
                resp[1] = actual.getValue().ordinal();
                break;
            }
        }
        return resp;
    }

    private boolean isRoyalFlush(Card[] input) {
        if (isFlush(input)) {
            return  input[0].getValue() == Rank.ACE 
                    && input[1].getValue() == Rank.TEN
                    && input[2].getValue() == Rank.JACK
                    && input[3].getValue() == Rank.QUEEN
                    && input[4].getValue() == Rank.KING;

        }
        return false;
    }

    private int[] straightFlush(Card[] input) {
        int[] resp = new int[3]; //Nótese que cuando es escalera de color
        resp[0] = 8;             // los dos siguientes son donde incia
        //donde termina
        resp[1] = input[0].getValue().ordinal();
        resp[2] = input[4].getValue().ordinal();
        return resp;
    }

    private boolean isFull(ArrayList<Card> lista) {
        if (threeOfAKind(lista)) {
            int vec[] = threeofK(lista);
            if (vec[2] == vec[3]) {
                return true;
            }
        }
        return false;
    }

    private int[] flush(Card[] input) { // Cuando es flush 
        int resp[] = new int[3];          //retorno el valor del Palo
        resp[0] = 5;                     // la carta más alta : en ese orden.
        resp[1] = input[0].getSult().ordinal();
        resp[2] = input[4].getValue().ordinal();
        return resp;
    }

    private int[] full(ArrayList<Card> input) {
        int resp[] = new int[3];
        int aux[] = threeofK(input);
        resp[0] = 6;
        resp[1] = aux[1];
        resp[2] = aux[2];
        return resp;
    }

    private boolean isFlush(Card[] input) {
        if (input.length < 4) {return false;}
            return ((input[0].getSult().equals(input[1].getSult()))
                    == (input[2].getSult().equals(input[3].getSult())))
                    == (input[0].getSult().equals(input[4].getSult()));
        
     
    }

    private boolean isStraight(ArrayList<Card> input) {
        if (input.size() < 4) {
            return false;
        }
        int aux =0; 
        for (int i = 0; i < input.size() - 1; i++) {
            aux = (input.get(i).getValue().ordinal() - input.get(i+1).getValue().ordinal());
      
            if ( aux!= -1) {
             return false;
            }
        }
        return true;
    }

    private int[] straight(ArrayList<Card> input) {
        int resp[]= new int[3];
        resp[0]=4;
        resp[1]=input.get(0).getValue().ordinal();
        resp[2]=input.get(4).getValue().ordinal();
        return resp;
    }


    private boolean threeOfAKind(ArrayList<Card> input) {
        for (int i = 0; i < input.size() - 2; i++) {
            Rank valor = input.get(i).getValue();
            if (valor.equals(input.get(i + 1).getValue()) && valor.equals(input.get(i + 2).getValue())) {
                return true;
            }
        }
        return false;
    }

    private boolean isTwoPairs(Card[] input) {
        for (int i = 0; i < input.length - 2; i++) {
            Rank valor1 = input[i].getValue();
            Rank valor2 = input[i + 2].getValue();
            if (valor1.equals(input[i + 1].getValue())
                    && valor2.equals(input[i + 2].getValue())) {
                return true;
            }
        }
        return false;
    }

    private int[] twoPairs(Card[] input) {
        int[] result = new int[4];
        result[0] = 2;
        for (int i = 0; i < input.length - 2; i++) {
            Rank valor = input[i].getValue();
            if (valor.equals(input[i + 1].getValue())) {
                result[1] = valor.ordinal();
            }
            valor = input[i+1].getValue();
             if (valor.equals(input[i + 2].getValue())) {
                result[2] = valor.ordinal();
            }
        }
        result[4] = input[input.length].getValue().getOrdinal();
        return result;
    }

    private boolean isPair(Card[] input) {
       
        for (int i = 0; i < input.length - 1; i++) {
            Rank valor = input[i].getValue();
            if (valor.equals(input[i + 1].getValue())) {
                return true;
            }
        }
        return false;
    }

    private int[] pair(Card[] input) {
        int[] resp = new int[3];
        resp[0] = 1;
        for (int i = 0; i < input.length - 1; i++) {
            Rank valor = input[i].getValue();
            if (valor.equals(input[i + 1].getValue())) {
                resp[1] = valor.ordinal();
                resp[2] = input[input.length- 1].getValue().ordinal();
                break;
            }
        }
        return resp;
    }

    private int[] threeofK(ArrayList<Card> listax) {
        ArrayList<Card> lista = new ArrayList(); //shame on me :(
        lista.addAll(listax);
        int[] resp = new int[4];
        resp[0] = 3;
        int aux = 0;

        for (int i = 0; i < lista.size() - 2; i++) {
            Rank valor = lista.get(i).getValue();
            if (valor.equals(lista.get(i + 1).getValue())
                    && valor.equals(lista.get(i + 2).getValue())) {
                aux = i;
                resp[1] = lista.get(i).getValue().ordinal();
                break;

            }


        }
        lista.remove(aux);
        lista.remove((aux - 1) + 1);
        lista.remove((aux - 2) + 2);
        Collections.sort(lista);//a sort change the life!
        resp[2] = lista.get(1).getValue().ordinal();
        resp[3] = lista.get(0).getValue().ordinal();
        return resp;

    }

    private int[] highCard(ArrayList<Card> lista) {
        int resp[] = new int[lista.size()];
        Collections.sort(lista);
        for (int i = 0; i < lista.size(); i++) {
            resp[i] = lista.get(i).getValue().ordinal();
        }
        return resp;
    }
}
